﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Windows;
#if NETFX_CORE
using Windows.UI.Xaml;
#endif

namespace UnitDriven
{
	public class TestGroup : ObservableObject, IRunTests
	{
		private TestContext _context;
		private string _name;
		private bool _isRunning;
		private bool _isExpanded;
		private ObservableCollection<IRunTests> _items = new ObservableCollection<IRunTests>();

		public Visibility IsVisible
		{
			get
			{
				return this.Items.Any(i => i.IsVisible == Visibility.Visible)
					? Visibility.Visible
					: Visibility.Collapsed;
			}
		}

		public bool IsRunning
		{
			get { return _isRunning; }
			private set
			{
				_isRunning = value;
				OnPropertyChanged("IsRunning");
				OnPropertyChanged("IsNotRunning");
			}
		}

		public bool IsNotRunning
		{
			get { return !IsRunning; }
			set { IsRunning = !value; }
		}

		public string Name { get { return _name; } }

		public IList<IRunTests> Items
		{
			get { return _items; }
		}

		public int Succeeded
		{
			get
			{
				var count = (from t in _items
							 select t.Succeeded)
							 .Sum();

				return count;
			}
		}

		public bool IsExpanded
		{
			get { return _isExpanded; }
			set { _isExpanded = value; this.OnPropertyChanged("IsExpanded"); }
		}

		public TestResult Status
		{
			get
			{
				if (_items.Any(item => item.Status == TestResult.Fail))
					return TestResult.Fail;
				if (_items.Any(item => item.Status == TestResult.Evaluating))
					return TestResult.Evaluating;
				if (_items.Any(item => item.Status == TestResult.Indeterminate))
					return TestResult.Indeterminate;

				return TestResult.Success;
			}
		}

		public TestGroup(TestContext context, string name)
		{
			if (context == null)
				throw new ArgumentNullException("context");
			if (string.IsNullOrEmpty(name))
				throw new ArgumentNullException("name");

			_context = context;
			_name = name;
			_items.CollectionChanged += ItemsCollectionChanged;
			_context.PropertyChanged += Context_PropertyChanged;
		}

		public void RunTests()
		{
			foreach (var item in _items.Where(i => i.IsVisible == Visibility.Visible))
				item.RunTests();
		}

		private void Context_PropertyChanged(object sender, PropertyChangedEventArgs e)
		{
			if (e.PropertyName == "Filter")
			{
				this.IsExpanded = true;
				this.OnPropertyChanged("IsVisible");
			}
		}

		private void ItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
		{
			switch (e.Action)
			{
				case NotifyCollectionChangedAction.Add:
					foreach (var item in e.NewItems)
						((IRunTests)item).PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(ItemPropertyChanged);
					break;
				default:
					throw new NotSupportedException();
			}
		}

		private void ItemPropertyChanged(object sender, PropertyChangedEventArgs e)
		{
			if (e.PropertyName == "IsRunning")
			{
				IsRunning = _items.Any(t => t.IsRunning);
				OnPropertyChanged("Succeeded");
				OnPropertyChanged("Status");
			}
		}
	}
}
